/****************************************************************
 * Fulguro
 * Copyright (C) 2004 Christophe Clienti
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 ***************************************************************/

#ifdef __cplusplus
extern "C" {
#endif


#ifndef __FLGR_DATA_TOOLS_FIFO_H
#define __FLGR_DATA_TOOLS_FIFO_H 

#include <flgrCoreDll.h>
#include <flgrCoreTypes.h>
#include <flgrCoreMalloc.h>

/*!
 * \defgroup group_fulguro_datatools_dynamic_fifo Dynamic Size Fifo
 * \brief Basic tools for manipulating Dynamic Size Fifo
 * \ingroup group_fulguro_datatools
 * @{
 */

  typedef struct FLGR_FifoLink FLGR_FifoLink; 
  
  /*! 
   * FIFO element
   */  
  struct FLGR_FifoLink { 
    FLGR_FifoLink *next;
    FLGR_FifoLink *previous;
    int z;
    int y;
    int x;
  }; 
  

  typedef struct FLGR_Fifo FLGR_Fifo; 

  /*! 
   * Dynamic size FIFO
   */  
  struct FLGR_Fifo{
    FLGR_FifoLink *input;   /*!< Fifo input pointer */
    FLGR_FifoLink *output;  /*!< Fifo output pointer */ 
    int size;               /*!< Fifo size */
    void *label;            /*!< Fifo label */
  };

  
  //////////////////////////////////////////////////////////////////
  /*! Initialize fifo
   *  @param fifo : FLGR_Fifo pointer
   *  @returns nothing
   */
  //////////////////////////////////////////////////////////////////
  EXPORT_LIB void flgr_fifo_init(FLGR_Fifo *fifo);

  //////////////////////////////////////////////////////////////////
  /*! Create a fifo
   *  @returns FLGR_Fifo pointer
   */
  //////////////////////////////////////////////////////////////////
  EXPORT_LIB FLGR_Fifo *flgr_fifo_create(void);

  //////////////////////////////////////////////////////////////////
  /*! Destroy a fifo
   *  @param fifo : FLGR_Fifo pointer
   *  @returns nothing
   */
  //////////////////////////////////////////////////////////////////
  EXPORT_LIB void flgr_fifo_destroy(FLGR_Fifo *fifo);

  //////////////////////////////////////////////////////////////////
  /*! Purge a fifo
   *  @param fifo : FLGR_Fifo pointer
   *  @returns nothing
   */
  //////////////////////////////////////////////////////////////////
  EXPORT_LIB void flgr_fifo_flush(FLGR_Fifo *fifo);

  //////////////////////////////////////////////////////////////////
  /*! Get fifo size
   *  @param fifo : FLGR_Fifo pointer
   *  @returns nothing
   */
  //////////////////////////////////////////////////////////////////
  EXPORT_LIB int flgr_fifo_get_size(FLGR_Fifo *fifo);


  //////////////////////////////////////////////////////////////////
  /*! Remove current output link
   *  @param fifo : FLGR_Fifo pointer
   *  @returns nothing
   */
  //////////////////////////////////////////////////////////////////
  static __inline__ void flgr_fifo_del_current(FLGR_Fifo *fifo) {
    FLGR_FifoLink *tmp;

    if(fifo->size==0) return;

    tmp = fifo->output;
    fifo->output = tmp->previous;
    fifo->size--;

    if(fifo->size==0) {
      fifo->input = NULL;
    }else {
      fifo->output->next=NULL;
    }

    flgr_free(tmp);    

  }

  //////////////////////////////////////////////////////////////////
  /*! Get the current output link without removing it
   *  @param fifo : FLGR_Fifo pointer
   *  @param *z : pointer to interger value for z-axis
   *  @param *y : pointer to interger value for y-axis
   *  @param *x : pointer to interger value for x-axis
   *  @returns nothing
   */
  //////////////////////////////////////////////////////////////////
  static __inline__ void flgr_fifo_get_current(FLGR_Fifo *fifo, int *z, int *y, int *x) {
    FLGR_FifoLink *tmp;
    tmp = fifo->output;
    *z=tmp->z;    
    *y=tmp->y;
    *x=tmp->x;
  }

  //////////////////////////////////////////////////////////////////
  /*! Push values
   *  @param fifo : FLGR_Fifo pointer
   *  @param z : z data
   *  @param y : y data
   *  @param x : x data
   *  @returns nothing
   */
  //////////////////////////////////////////////////////////////////
  static __inline__ void flgr_fifo_push(FLGR_Fifo *fifo, int z, int y, int x) {
    FLGR_FifoLink *tmp = (FLGR_FifoLink*) flgr_malloc(sizeof(FLGR_FifoLink));

    tmp->next = fifo->input;
    tmp->previous = NULL;
    tmp->z = z;
    tmp->y = y;
    tmp->x = x;
    
    if(fifo->size==0) {
      fifo->output = tmp;
    }else {
      fifo->input->previous = tmp;
    }

    fifo->input = tmp; 

    fifo->size++;
  }

  //////////////////////////////////////////////////////////////////
  /*! Pop values (get the current value and remove it)
   *  @param fifo : FLGR_Fifo pointer
   *  @param *z : pointer to z data
   *  @param *y : pointer to y data
   *  @param *x : pointer to x data
   *  @returns nothing
   */
  //////////////////////////////////////////////////////////////////
  static __inline__ void flgr_fifo_pop(FLGR_Fifo *fifo, int *z, int *y, int *x) {
    flgr_fifo_get_current(fifo,z,y,x);
    flgr_fifo_del_current(fifo);
  }



//! @}


#endif

#ifdef __cplusplus
}
#endif
